/* __auth__ : KunLin */

package com.mall.shopping.services;

import com.alibaba.fastjson.JSON;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import com.mall.shopping.ICartService;
import com.mall.shopping.constant.GlobalConstants;
import com.mall.shopping.constants.ShoppingRetCode;
import com.mall.shopping.converter.CartItemConverter;
import com.mall.shopping.dal.entitys.Item;
import com.mall.shopping.dal.persistence.ItemMapper;
import com.mall.shopping.dto.*;
import com.mall.shopping.services.cache.CacheManager;
import com.mall.shopping.utils.ExceptionProcessorUtils;
import jdk.nashorn.internal.ir.annotations.Reference;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Service;
import org.checkerframework.checker.units.qual.K;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;


@Slf4j
@Service
public class ICartServiceImpl implements ICartService {
    @Autowired
    RedissonClient redissonClient;


    @Autowired
    CacheManager cacheManager;

    @Autowired
    ItemMapper itemMapper;

    @Autowired
    Gson gson;

    @Override
    public CartListByIdResponse getCartListById(CartListByIdRequest request) {
        CartListByIdResponse response = new CartListByIdResponse();
        request.requestCheck();
        List<CartProductDto> cartProductDtoList = null;
        try {
            //直接拿到的是uid
            CartListByIdResponse cartListByIdResponse = new CartListByIdResponse();

            //获取购物车所有商品信息
            RMap<Object, Object> map = redissonClient.getMap(generatorCartItemKey(request.getUserId()));
            //遍历
            cartProductDtoList = new ArrayList<>();

            for (Map.Entry entry : map.entrySet()) {
                String value = (String) entry.getValue();
                CartProductDto cartProductDto = gson.fromJson(value, CartProductDto.class);
                cartProductDtoList.add(cartProductDto);
            }
        } catch (JsonSyntaxException e) {
            e.printStackTrace();
            log.error("com.mall.shopping.services.ICartServiceImpl.getCartListById occur Exception :" + e);
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }

        response.setCartProductDtos(cartProductDtoList);
        response.setCode(ShoppingRetCode.SUCCESS.getCode());
        response.setMsg(ShoppingRetCode.SUCCESS.getMessage());
        return response;
    }

    private String generatorCartItemKey(long userId) {
        StringBuilder sb = new StringBuilder(GlobalConstants.CART_ITEM_CACHE_PREFIX);
        sb.append(":").append(userId);
        return sb.toString();
    }

    @Override
    public AddCartResponse addToCart(AddCartRequest request) {
        request.requestCheck();

        AddCartResponse addCartResponse = new AddCartResponse();
        addCartResponse.setCode(ShoppingRetCode.SUCCESS.getCode());
        addCartResponse.setMsg(ShoppingRetCode.SUCCESS.getMessage());

        try {
            //根据用户id在redis中返回map
            Map<Object, Object> redissonClientMap = redissonClient.getMap(generatorCartItemKey(request.getUserId()));

            //判断购物车中此商品是否已存在
            boolean exist = redissonClientMap.containsKey(request.getItemId());

            //打印操作日志
            log.info("to add item " + request.getItemId() + "to " + generatorCartItemKey(request.getUserId()));

            CartProductDto cartProductDto = null; //根据情况给dto赋值

            //判断是否需要合并购物车
            if (exist) {//商品已存在，改变购物车中数量
                Object o = redissonClientMap.get(request.getItemId()); //通过key（商品id）得到redis中存储的序列化数据

                //将数据解析赋值给dto
                cartProductDto = JSON.parseObject(o.toString(), CartProductDto.class);
                cartProductDto.setProductNum(cartProductDto.getProductNum() + request.getNum());
            } else { //商品尚未存在，在购物车中增加商品信息
                Item item = itemMapper.selectByPrimaryKey(request.getItemId());

                if (item == null) {
                    addCartResponse.setCode(ShoppingRetCode.SYSTEM_ERROR.getCode());
                    addCartResponse.setMsg(ShoppingRetCode.SYSTEM_ERROR.getMessage());
                    return addCartResponse;

                }

                //为dto赋值
                cartProductDto = CartItemConverter.item2Dto(item);
                cartProductDto.setChecked("true");
                cartProductDto.setProductNum(request.getNum().longValue());
            }

            redissonClientMap.put(request.getItemId(), JSON.toJSON(cartProductDto).toString());
        } catch (Exception e) {
            log.error("CartServiceImpl.addToCart occurs error " + e);
            ExceptionProcessorUtils.wrapperHandlerException(addCartResponse, e);
        }

        return addCartResponse;
    }

    @Override
    public UpdateCartNumResponse updateCartNum(UpdateCartNumRequest request) {

        request.requestCheck();

        UpdateCartNumResponse updateCartNumResponse = new UpdateCartNumResponse();
        updateCartNumResponse.setCode(ShoppingRetCode.SUCCESS.getCode());
        updateCartNumResponse.setMsg(ShoppingRetCode.SUCCESS.getMessage());

        try {
            String key = generatorCartItemKey(request.getUserId());
            log.info("to update " + key + "cart item " + request.getItemId());

            RMap<Object, Object> redissonClientMap = redissonClient.getMap(key);
            Object o = redissonClientMap.get(request.getItemId());

            if (o != null) {
                //redis所存对象非空，将其转为dto
                CartProductDto cartProductDto = JSON.parseObject(o.toString(), CartProductDto.class);

                //数量若为0，可能需要删除
                log.info("before num = " + cartProductDto.getProductNum());
                cartProductDto.setProductNum(request.getNum().longValue()); //修改商品数量

                log.info("after num = " + cartProductDto.getProductNum());

                log.info("before checked = " + cartProductDto.getChecked() );
                cartProductDto.setChecked(request.getChecked()); //修改选择状态
                log.info("after checked = " + cartProductDto.getChecked() );

                redissonClientMap.put(request.getItemId(), JSON.toJSON(cartProductDto).toString());
            }
        } catch (Exception e) {
            log.error("CartServiceImpl.updateCartNum Occur Exception :" + e);
            ExceptionProcessorUtils.wrapperHandlerException(updateCartNumResponse, e);

        }

        return updateCartNumResponse;
    }

    @Override
    public CheckAllItemResponse checkAllCartItem(CheckAllItemRequest request) {

        CheckAllItemResponse response = new CheckAllItemResponse();
        try {
            request.requestCheck();
            Map<Object, Object> redissonClientMap = redissonClient.getMap(generatorCartItemKey(request.getUserId()));
            redissonClientMap.forEach((key, val)->{
                CartProductDto cartProductDto = gson.fromJson(val.toString(), CartProductDto.class);
                cartProductDto.setChecked(request.getChecked());
                redissonClientMap.replace(key, gson.toJson(cartProductDto));
            });

            response.setCode(ShoppingRetCode.SUCCESS.getCode());
            response.setMsg(ShoppingRetCode.SUCCESS.getMessage());
        } catch (Exception e) {
            response.setMsg("com.mall.shopping.services.ICartServiceImpl occur Exception :" + e);
            log.error("com.mall.shopping.services.ICartServiceImpl occur Exception :" + e);
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }
        return response;
    }

    @Override
    public DeleteCartItemResponse deleteCartItem(DeleteCartItemRequest request) {

        request.requestCheck();

        DeleteCartItemResponse deleteCartItemResponse = new DeleteCartItemResponse();
        deleteCartItemResponse.setCode(ShoppingRetCode.SUCCESS.getCode());
        deleteCartItemResponse.setMsg(ShoppingRetCode.SUCCESS.getMessage());
        log.info("to delete " + request.getItemId() + " from " + generatorCartItemKey(request.getUserId()));

        try {
            RMap<Object, Object> redissonClientMap = redissonClient.getMap(generatorCartItemKey(request.getUserId()));
            redissonClientMap.remove(request.getItemId());
        } catch (Exception e) {
            log.error("CartServiceImpl.deleteCartItem Occur Exception :" + e);
            ExceptionProcessorUtils.wrapperHandlerException(deleteCartItemResponse, e);
        }
        return deleteCartItemResponse;
    }

    @Override
    public DeleteCheckedItemResposne deleteCheckedItem(DeleteCheckedItemRequest request) {
        DeleteCheckedItemResposne response = new DeleteCheckedItemResposne();
        try {
            request.requestCheck();
            // TODO 查询Redis后删除数
            Map<Object, Object> redissonClientMap = redissonClient.getMap(generatorCartItemKey(request.getUserId()));
            List<Object> keys = new LinkedList<>();
            redissonClientMap.forEach((key, val)->{
                CartProductDto cartProductDto = gson.fromJson(val.toString(), CartProductDto.class);
                if ("true".equals(cartProductDto.getChecked())) {
                    keys.add(key);
                }
            });
            for (Object key : keys) {
                redissonClientMap.remove(key);
            }
            response.setCode(ShoppingRetCode.SUCCESS.getCode());
            response.setMsg(ShoppingRetCode.SUCCESS.getMessage());
        } catch (Exception e) {
            response.setMsg("com.mall.shopping.services.ICartServiceImpl occur Exception :" + e);
            log.error("com.mall.shopping.services.ICartServiceImpl occur Exception :" + e);
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }
        return response;
    }

    @Override
    public ClearCartItemResponse clearCartItemByUserID(ClearCartItemRequest request) {
        return null;
    }
}
